/**
 *  \file   timer.c
 *  \author Miora ANDRIAMANOHARISOA, Loic MINGHETTI
 *  \date   PFE 2011
 **/


#include "include.h"

// timer tables

uint16_t timers[NUM_TIMERS];
static timer_watch_cb timers_watch[NUM_TIMERS];
static uint16_t timers_watch_period[NUM_TIMERS];


// register a short callback on timer reach given value. Will execute on timer interruption. To unregister, set cb = null
void timer_watch (uint16_t* p_timer, timer_watch_cb cb, uint16_t count) {
	timer_watch_cb * timer_cb;
	uint16_t * timer_period;
	
	timer_cb = (timer_watch_cb *) ((int) p_timer - (int) &timers[0] + (int) &timers_watch[0]);
	*timer_cb = cb;
	
	timer_period = (uint16_t *) ((int) p_timer - (int) &timers[0] + (int) &timers_watch_period[0]);
	*timer_period = count;
	
}

void timer_unwatch (uint16_t * p_timer) {
	timer_watch(p_timer, NULL, -1);
}

void timer_reset (uint16_t * p_timer) {	
	*p_timer = 0;
}

void timer_on_tick() {
    int i;
    for(i = 0; i < NUM_TIMERS; i++) {
        if(timers[i] != UINT_MAX) {
            timers[i]++;
            // if a callback is registered and timeout elapsed
            if (timers[i] >= timers_watch_period[i] && timers_watch[i] != NULL) {
            	timers[i] = 0; // reset before calling callback
            	(timers_watch[i])();
            }
        }
    }
}

int timer_reached(uint16_t * p_timer, uint16_t count) {
    return (*p_timer >= count);
}


void timers_init() {

	/* clock init */
	set_mcu_speed_dco_mclk_16MHz_smclk_8MHz();
	int i;
    for(i = 0; i < NUM_TIMERS; i++) {
        timers[i] = 0;
        timers_watch[i] = NULL;
        timers_watch_period[i] = -1;
    }
        
    
	/* timer init */
	timerA_init();
	timerA_set_wakeup(1);
	timerA_register_cb(&timer_on_tick);
	timerA_start_milliseconds(TIMER_PERIOD_MS);

}
